package com.cloudinnov.logic.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

import com.cloudinnov.dao.ScheduleJobDao;
import com.cloudinnov.logic.JobTaskLogic;
import com.cloudinnov.task.QuartzJobFactory;
import com.cloudinnov.task.QuartzJobFactoryDisallowConcurrentExecution;
import com.cloudinnov.task.model.ScheduleJob;
import com.cloudinnov.utils.CommonUtils;

/**
 * 计划任务管理
 * @ClassName: JobTaskLogic
 * @Description: TODO
 * @author: ningmeng
 * @date: 2016年11月29日 上午11:39:24
 */
@Service("jobTaskLogic")
public class JobTaskLogicImpl implements JobTaskLogic {
	private static final Logger LOG = LoggerFactory.getLogger(JobTaskLogicImpl.class);
	public static final String TIGGER_CLASS_PATH = "com.cloudinnov.task.TriggerQuartzJob";
	public static final String TIGGER_CLASS_METHOD = "execute";
	public static final String ALARMRULE_CLASS_PATH = "com.cloudinnov.task.AlarmRuleQuartzJob";
	public static final String JOB_START_CMD = "start";
	public static final String JOB_STOP_CMD = "stop";
	public final Logger log = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private SchedulerFactoryBean schedulerFactoryBean;
	@Autowired
	private ScheduleJobDao scheduleJobDao;

	/**
	 * 获取一个任务详情
	 * @return
	 */
	public ScheduleJob selectTask(ScheduleJob model) {
		return scheduleJobDao.selectEntityByCondition(model);
	}
	/**
	 * 从数据库中取 区别于getAllJob
	 * @return
	 */
	public List<ScheduleJob> getAllTask() {
		return scheduleJobDao.selectListByCondition(null);
	}
	/**
	 * 添加到数据库中 区别于addJob
	 */
	public int addTask(ScheduleJob job) {
		job.setCreateTime(new Date());
		return scheduleJobDao.insert(job);
	}
	/**
	 * 从数据库中查询job
	 */
	public ScheduleJob getTaskById(Long jobId) {
		ScheduleJob model = new ScheduleJob();
		model.setJobId(jobId);
		return scheduleJobDao.selectEntityByCondition(model);
	}
	/**
	 * 更改任务状态
	 * @throws SchedulerException
	 */
	public void changeStatus(Long jobId, String cmd) {
		ScheduleJob job = getTaskById(jobId);
		if (job == null) {
			return;
		}
		try {
			if (JOB_STOP_CMD.equals(cmd)) {
				deleteJob(job);
				job.setJobStatus(ScheduleJob.STATUS_NOT_RUNNING);
			} else if (JOB_START_CMD.equals(cmd)) {
				job.setJobStatus(ScheduleJob.STATUS_RUNNING);
				addJob(job);
			}
		} catch (SchedulerException e) {
			LOG.error("changeStatus is error, data: {}, error: {}, cmd : {}", job, e, cmd);
		}
		scheduleJobDao.updateByCondition(job);
	}
	/**
	 * 更改任务 cron表达式
	 * @throws SchedulerException
	 */
	@Override
	public void updateCron(Long jobId, String cron) {
		ScheduleJob job = getTaskById(jobId);
		if (job == null) {
			return;
		}
		job.setCronExpression(cron);
		if (ScheduleJob.STATUS_RUNNING.equals(job.getJobStatus())) {
			try {
				updateJobCron(job);
			} catch (SchedulerException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		scheduleJobDao.updateByCondition(job);
	}
	/**
	 * 添加任务
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void addJob(ScheduleJob job) {
		if (job == null || !ScheduleJob.STATUS_RUNNING.equals(job.getJobStatus())) {
			return;
		}
		try {
			log.debug("后台任务初始化成功:\t" + job);
			Scheduler scheduler = schedulerFactoryBean.getScheduler();
			log.debug(scheduler + job.getJobName() + job.getJobGroup() + "add");
			TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			// 不存在，创建一个
			if (null == trigger) {
				Class clazz = ScheduleJob.CONCURRENT_IS.equals(job.getIsConcurrent()) ? QuartzJobFactory.class
						: QuartzJobFactoryDisallowConcurrentExecution.class;
				JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup())
						.build();
				jobDetail.getJobDataMap().put("scheduleJob", job);
				CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
				trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup())
						.withSchedule(scheduleBuilder).build();
				scheduler.scheduleJob(jobDetail, trigger);
			} else {
				// Trigger已存在，那么更新相应的定时设置
				CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
				// 按新的cronExpression表达式重新构建trigger
				trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
				// 按新的trigger重新设置job执行
				scheduler.rescheduleJob(triggerKey, trigger);
			}
		} catch (SchedulerException e) {
			LOG.error("addJob is error, data: {}, error: {}, cmd : {}", job, e);
		}
	}
	@PostConstruct
	public void init() throws Exception {
		ScheduleJob model = new ScheduleJob();
		model.setRun(ScheduleJob.IS_NOT_RUNING);
		model.setEnv(CommonUtils.ENV);
		// 获取所有任务
		List<ScheduleJob> jobList = scheduleJobDao.getAll(model);
		for (ScheduleJob job : jobList) {
			addJob(job);
		}
	}
	/**
	 * 获取所有计划中的任务列表
	 * @return
	 * @throws SchedulerException
	 */
	public List<ScheduleJob> getAllJob() throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
		Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
		List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();
		for (JobKey jobKey : jobKeys) {
			List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
			for (Trigger trigger : triggers) {
				ScheduleJob job = new ScheduleJob();
				job.setJobName(jobKey.getName());
				job.setJobGroup(jobKey.getGroup());
				job.setDescription("触发器:" + trigger.getKey());
				Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
				job.setJobStatus(triggerState.name());
				if (trigger instanceof CronTrigger) {
					CronTrigger cronTrigger = (CronTrigger) trigger;
					String cronExpression = cronTrigger.getCronExpression();
					job.setCronExpression(cronExpression);
				}
				jobList.add(job);
			}
		}
		return jobList;
	}
	/**
	 * 所有正在运行的job
	 * @return
	 * @throws SchedulerException
	 */
	public List<ScheduleJob> getRunningJob() {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		List<ScheduleJob> jobList = null;
		try {
			List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
			jobList = new ArrayList<ScheduleJob>(executingJobs.size());
			for (JobExecutionContext executingJob : executingJobs) {
				ScheduleJob job = new ScheduleJob();
				JobDetail jobDetail = executingJob.getJobDetail();
				JobKey jobKey = jobDetail.getKey();
				Trigger trigger = executingJob.getTrigger();
				job.setJobName(jobKey.getName());
				job.setJobGroup(jobKey.getGroup());
				job.setDescription("" + trigger.getKey());
				Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
				job.setJobStatus(triggerState.name());
				if (trigger instanceof CronTrigger) {
					CronTrigger cronTrigger = (CronTrigger) trigger;
					String cronExpression = cronTrigger.getCronExpression();
					job.setCronExpression(cronExpression);
				}
				jobList.add(job);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
		return jobList;
	}
	/**
	 * 暂停一个job
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void pauseJob(ScheduleJob scheduleJob) throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.pauseJob(jobKey);
	}
	/**
	 * 恢复一个job
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void resumeJob(ScheduleJob scheduleJob) throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.resumeJob(jobKey);
	}
	/**
	 * 删除一个job
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void deleteJob(ScheduleJob scheduleJob) throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.deleteJob(jobKey);
	}
	/**
	 * 立即执行job
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void runAJobNow(ScheduleJob scheduleJob) throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		scheduler.triggerJob(jobKey);
	}
	/**
	 * 更新job时间表达式
	 * @param scheduleJob
	 * @throws SchedulerException
	 */
	public void updateJobCron(ScheduleJob scheduleJob) throws SchedulerException {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
		CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
		CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
		trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
		scheduler.rescheduleJob(triggerKey, trigger);
	}
}
